// function add(getX, getY, callback) {
//     var x, y; // 未来值
//     getX(function(xval) {
//         x = xval;
//         if (y) {
//             callback(x + y);
//         }
//     })

//     getY(function(yval) {
//         y = yval;
//         if (x) {
//             callback(x + y);
//         }
//     })
// }

// add(fetchX, fetchY, (sum) => {
//     console.log(sum);
// })


// function add(xp, yp) {
//     return Promise.all([ xp, yp ]).then((values) => {
//         return values[0] + values[1]
//     })
// }

// add(fetchX, fetchY).then((sum) => { console.log(sum) })

// function foo(x) {
//     // ... 构造listener事件通知处理对象来返回
//     return listener;
// }

// const eve = foo(1);

// eve.on('completion', () => {
//     // next step
// });

// eve.on('failure', () => {
//     // error
// });

function foo(x) {
    return new Promise((resolve, reject) => {})
}

const p = foo(1);

// bar(p);


// function bar (promise) {
//     // xxx
//     promise.then(
//         function() {},
//         function() {}
//     );
// }

function bar() {
    //..
}

function baz() {
    // ...
}

function error() {
    // xxx
}

p.then(bar, error)
p.then(baz, error)

// 对thenable值的鸭子类型检查
if (
    p !== null && (
        typeof p === 'object' ||
        typeof p === 'function'
    ) &&
    typeof p.then === 'funciton'
) {
    // 假定这是个thenable
}

// 其他方案 branding/anti-branding

// const o = { then: function() {} }

// const v = Object.create(o)

// 信任问题 - 调用过早
// Zalgo -> 竞态条件
// 信任问题 - 调用过晚

// bad case
// const p3 = new Promise((resolve, reject) => {
//     resolve('B');
// })

// const p1 = new Promise((resolve, reject) => {
//     resolve(p3)
// })

// const p2 = new Promise((resolve, reject) => {
//     resolve('A');
// })

// p1.then((v) => {
//     console.log(v);
// })

// p2.then((v) => {
//     console.log(v);
// })

// 信任问题 - 未调用
function timeoutPromise(delay = 3000) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('timeout');
        }, delay);
    })
}

Promise.race([ request(), timeoutPromise(1500) ]);

const p = new Promise((resolve, reject) => {
    resolve(1)
})

p.then((v) => {
    foo.bar() // p.then返回的promise因为TypeError被拒绝了
    console.log(v);
}, (err) => {
    console.log(err);
})

// const p1 = new Promise((resolve, reject) => {
//     resolve(1)
// })

// const p2 = Promise.resolve(1)

// const p3 = Promise.resolve(1)
// const p4 = Promise.resolve(p3)

// const p = Promise.resolve(2)
// p.then((v) => {
//     console.log(v);
//     return new Promise((resolve) => {
//         setTimeout(() => {
//             resolve(v * 2)
//         }, 0)
//     })
// }).then((v) => {
//     console.log(v);
// })

function request(url) {
    return new Promise((reslove) => {
        ajax(url, resolve)
    })
}

request('http://www.1.com')
.then((res1) => {
    foo.bar() // error
    return request(`http://www.2.com?${res1}`);
}, (err) => {
    console.log(err);
})
.then((res2) => {
    console.log(res2);
},(err) => {
    // TypeError
    console.log(err);
})

// 错误处理
// 常规 -> error-first
// Promise -> split-callback

const p = Promise.resolve(2);

p.then((v) => {
    console.log(v.toLowerCase()); // error
})
.catch((error) => {
    foo.bar();
    console.log(error);
})

// Promise api
// all - gate机制
Promise.all([p1, p2, p3])
// 任一失败 直接跳出
// race - 竞态
Promise.race([p1, p2, p3])
// 按第一个返回结果进行后续处理
Promise.finally
// none
// any
// first
// last

// Promise.map
Promise.map = function(vals, cb) {
    return Promise.all(
        vals.map((val) => {
            return new Promise((resolve) => {
                cb(val, resolve)
            })
        })
    )
}

// api总结
// new Promise()
// Promise.resolve() & Promise.reject()
// then & catch
// all race

// Promise局限性
// 顺序错误处理
// foo, Step2, Step3 -> Promise
const p = foo(1).then(STEP2).then(STEP3);
p.catch(handleError)
// 单一值
function getX(x) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve((3 * x) - 1)
        }, 100)
    })
}

function foo(bar, baz) {
    const x = bar * baz;
    return [
        Promise.resolve(x),
        getX(x)
    ]
}

Promise.all(foo(10, 20)).then(([x, y]) => {
    console.log(x, y);
})
// 单次变更 - RxJS
// const p = new Promise((resolve, reject) => {
//     click('#btn', resolve)
// })
// p.then((e) => {
//     const id = e.currentTarget.id;
//     return request(`http://www.abc.com?${id}`)
// }).then((result) => {
//     console.log(result);
// })

click('#btn', (e) => {
    const id = e.currentTarget.id;
    request(`http://www.abc.com?${id}`).then((res) => {
        console.log(res);
    })
});
// 惯性
function foo(a, b, cb) {
    ajax(`http://www.abc.com?${x}&${y}`, cb)
};
foo(10, 20, (err, res) => {
    if (err) {
        console.log(err);
        return;
    }
    console.log(res);
});

Promise.wrap = (fn) => {
    return function() {
        const args = [].slice.call(arguments);
        return new Promise((resolve, reject) => {
            fn.apply(
                null,
                args.concat((err, v) => {
                    if (err) {
                        reject(err)
                    }
                    resolve(v)
                })
            )
        })
    }
}

const request = Promise.wrap(ajax);
request(`http://www.abc.com?${x}&${y}`).then()

// Promise无法取消
let OK = true;
const p = foo(21);
Promise.race([p, timeoutPromise(3000).catch((e) => { OK = false; throw err })]).then(success, fail)
p.then(() => {
    if (OK) {
        // ...
    }
})

// 额外类库 - 取消
// 性能问题
